//global depenencies
global.$ = {};
global.$.Deferred 	= require( "JQDeferred" );
global.$.when		= $.Deferred.when;

global.languages  	= require("../src/languages");
global.language   	= require("../src/language");
global.when 	  	= require("../src/utils").when;
global.debug 	  	= require("../src/utils").debug;


var mockFS 		 	= require("./fs");
var fs 				= require("fs");
var assert 			= require("assert");
var exec 			= require('child_process').exec;
var utils  			= require("../../preprocessing/src/utils");



describe('Language module tests', function() {

	before(function(done) {
		exec('node ../../preprocessing/execute -i ./data/preprocessing_input -o ./out/global',
		  function (error, stdout, stderr) {
		  	console.log(stdout)
		    if (error !== null) {
		      done(error);
		      return;
		    }
		    done();
		});
	});

	describe('Language', function() {

		describe('loads', function() {

			it('from global', function(done) {
				var fileSystem = {
					local 	: new mockFS.Local (),
					remote  : new mockFS.Remote(),
					global  : new mockFS.Global("./out/global/")
				}
				var langs = new languages.Languages(fileSystem);
				langs.init()
				.then(function() {
					var referenceGlobal = JSON.parse(fs.readFileSync("./out/global/manifest.json"));
					assert.deepEqual(referenceGlobal, langs.mManifests.global.manifest);
					assert(!fileSystem.remote.existsSync("manifest.json"));
					assert(!fileSystem.local.existsSync("manifest.json"));

					var referenceTestLanguageGlobal = JSON.parse(fs.readFileSync("./out/global/languages/TestLanguage/manifest.json"));
					var testLanguage = langs.languages()["TestLanguage"];
					assert(testLanguage);
					assert.deepEqual(referenceTestLanguageGlobal, testLanguage.mManifests.global.manifest);
					assert(testLanguage.mManifests.personal.manifest.sessionId);
					for (var property in testLanguage.mManifests.personal.manifest) {
						if (property === "sessionId") {
						} else if (property === "name") {
							assert.equal(testLanguage.mManifests.personal.manifest.name, "TestLanguage");
						} else if (property === "timestamp") {
							assert.equal(testLanguage.mManifests.personal.manifest.timestamp, referenceTestLanguageGlobal.timestamp);
						} else if (property === "cuts") {
							assert.deepEqual(testLanguage.mManifests.personal.manifest.cuts, {});
						} else {
							assert(false, "fresh testLanguage manifest has unexpected property: '"+property+"'");
						}
					}
					done();
				})
				.fail(function(error) {
					done(error);
				});
			});
		});

		it('serves entries', function(done) {
			var testLanguage = undefined;
			var fileSystem = {
				local 	: new mockFS.Local (),
				remote  : new mockFS.Remote(),
				global  : new mockFS.Global("./out/global/")
			}
			var langs = new languages.Languages(fileSystem);
			langs.init()
			.then(function() {
				testLanguage = langs.languages()["TestLanguage"];
				testLanguage.begin({
					loading : 2,
					stepFunction : function() {return 0.5},
					saveLocalEveryImpressions : 2,
					saveRemoteEveryLocalSaves : 2
				});
			})
			.then(function() {
				var entry = testLanguage.nextWord();
				assert.equal(entry.entry.word, "noun01");
				assert.equal(entry.entry.properties.scores["basic"].score, 1);
				assert.equal(entry.entry.properties.scores["basic"].impressions, 1);
				entry.feedback(0);
				for (elem in fileSystem.local.mFileCache) {
					assert(false, "Didn't expect anything in local storage after loading from global fs, and found: '"+JSON.stringify(elem)+"'");
				}

				entry = testLanguage.nextWord();
				assert.equal(entry.entry.word, "noun02");
				assert.equal(entry.entry.properties.scores["basic"].score, 1);
				assert.equal(entry.entry.properties.scores["basic"].impressions, 1);
				entry.feedback(0);
				for (elem in fileSystem.remote.mFileCache) {
					assert(false, "Didn't expect anything in remote storage after loading from global fs, and found: '"+JSON.stringify(elem)+"'");
				}
				var globalManifest = JSON.parse(fs.readFileSync("./out/global/languages/TestLanguage/manifest.json"));
				var localManifest  = JSON.parse(fileSystem.local.readSync("languages/TestLanguage/manifest.json"));
				var parcelOne      = JSON.parse(fileSystem.local.readSync("languages/TestLanguage/adjectives_verbs_nouns/data00000000.json"));
				assert(globalManifest.timestamp);
				assert.equal(globalManifest.timestamp, localManifest.timestamp);
				assert(localManifest.sessionId);
				assert.equal(localManifest.cuts["adjectives_verbs_nouns"].parcels.length, 1);
				assert.equal(localManifest.cuts["adjectives_verbs_nouns"].parcels[0].path, "adjectives_verbs_nouns/data00000000.json");
				assert.equal(localManifest.cuts["adjectives_verbs_nouns"].parcels[0].sessionId, localManifest.sessionId);
				assert.equal(parcelOne["noun01"].scores["basic"].score, 1);
				assert.equal(parcelOne["noun01"].scores["basic"].impressions, 1);

				entry = testLanguage.nextWord();
				entry.feedback(1);
				assert.equal(entry.entry.word, "noun01");
				assert.equal(entry.entry.properties.scores["basic"].score, 0.7);
				assert.equal(entry.entry.properties.scores["basic"].impressions, 2);
				assert.equal(testLanguage.mWorkingSetArray.length, 3);
				done();
			})
			.fail(function(error) {
				done(error);
			});
		});
	});

	describe('Parcel', function() {

		describe('loads', function() {

			/*Basic starting condition, local and remote file systems present, but empty (first time use case)*/
			it('from global', function(done) {
				var fileSystem = {
					local 	: new mockFS.Local (),
					remote  : new mockFS.Remote(),
					global  : new mockFS.Global("./out/global/")
				}
				var langs = new languages.Languages(fileSystem);
				langs.init()
				.then(function() {
					for (elem in fileSystem.local.mFileCache) {
						assert(false, "Didn't expect anything in local storage after loading from global fs, and found: '"+JSON.stringify(elem)+"'");
					}
					assert(fileSystem.local)
					var testLanguage = langs.languages()["TestLanguage"];
					return testLanguage.getParcel("adjectives_verbs_nouns", 0);
				})
				.then(function(parcel) {
					assert("noun01" in parcel.mData);
					var localFiles = fileSystem.local.modifiedFiles();
					for (var file in localFiles) {
						assert(false, "Didn't expect anything in the local file system, found this:\n"+JSON.stringify(localFiles));
					}
					done();
				})
				.fail(function(error) {
					done(error);
				});
			});

			/*More complicated starting condition, user picks up a lesson started/saved on another device (for some reason, global file system is empty)*/
			it('from remote', function(done) {
				var testLanguage = undefined;
				var fileSystem = {
					local 	: new mockFS.Local (),
					remote  : new mockFS.Remote("./out/global/"),
					global  : new mockFS.Global()
				}
				var langs = new languages.Languages(fileSystem);
				langs.init()
				.then(function() {
					testLanguage = langs.languages()["TestLanguage"];
					return testLanguage.getParcel("adjectives_verbs_nouns", 0);
				})
				.then(function(parcel) {
					assert("noun01" in parcel.mData);
					assert(!fileSystem.local.existsSync("manifest.json"));
					done();
				})
				.fail(function(error) {
					done(error);
				});
			});
		});
	});

	after(function() {
		//utils.rmdirSyncForce("./.scratch");
		//utils.rmdirSyncForce("./out");
	});
});